package com.myapi.ModelPoker;
import java.io.Serializable;
import java.util.*;

import com.myapi.client.PotContributionInfo;
import com.myapi.client.DAO.TablePotDAO;

/**
 * A TablePot represents a pot in poker which is the combination of all bets for that hand, over the various betting rounds. 
 * Most hands usually only require one pot, but when a Player has bet all their chips into the pot and there are two or more other Players remaining in the pot (with more chips), 
 * these other Players may wish to continue betting against each other. In this case the Player who is "all in" can only win the pot which contains their all in bet plus the matched bets of the other Players. When the other Players have matched the all in and begin betting more, a side pot is created for them. A side pot can only be won by the Players who have contributed to it, even if the original all in Player has a better hand than a side pot Player. 
 * @author Realease by Yoan Olivier 
 *
 */
public class TablePot extends Observable implements Serializable {
    
    private List<PotContribution> contributions;
    private boolean closed;
    private boolean playerAllIn;
        
    /**
     * Constructor TablePot
     */
    public TablePot() {
        contributions = new ArrayList<PotContribution>();
        setClosed(false);
        setPlayerAllIn(false);
    }
    
    /**
     * Add a contribution in the TablePot
     * @param pCon PotContribution
     * @param notify
     */
    public void addContribution(PotContribution pCon, boolean notify) {
        int index = contributions.indexOf(pCon);
        if(index < 0) {
            contributions.add(pCon);
        } else {
            PotContribution matchC = contributions.get(index);
            matchC.setAmount(pCon.getAmount() + matchC.getAmount());
            matchC.setAllIn(pCon.getAllIn());
            matchC.setForced(pCon.getForced());
        }    
        if(pCon.getAllIn())
            setPlayerAllIn(true);        
        if(notify) {
            setChanged();
            notifyObservers();
        }
    }
    
    
    /**
     * @param Player
     * @return returns the current pot contribution for that player (if incomplete)
     */
    public PotContribution getPlayerContribution(Player player) {
        for(int i = 0; i < contributions.size(); i++) {
            PotContribution potC = contributions.get(i);
            Player tempP = potC.getPlayer();
            if(tempP.equals(player) && !potC.getComplete())
                return potC;     
        }
        return null;
    }
 
   /**
    * @param Player
    * @return returns a list of all pot contributions for that player including closed contributions
    */
    public List<PotContribution> getAllPlayerContributions(Player player) {
        List<PotContribution> potConts = getContributions();
        List<PotContribution> playerConts = new ArrayList<PotContribution>();
        for(int i = 0; i < potConts.size(); i++) {
            PotContribution potC = potConts.get(i);
            if(potC.getPlayer().equals(player))
                playerConts.add(potC);            
        }        
        return playerConts;
    }
    
    /**
     * @param Player
     * sets the forced value to false for the PotContribution from that Player (inidcating they have checked a forced bet)
     */
    public void contributionChecked(Player player) {
        PotContribution potC = getPlayerContribution(player);
        if(potC == null) {
            System.out.println("Cannot check a non-existant bet!");
        } else {
            potC.setForced(false);
            setChanged();
            notifyObservers();
        }
    }
    
    /**
     * Muck the player's contribution
     * @param player
     */
    public void muckContributions(Player player) {
        List<PotContribution> potConts = getAllPlayerContributions(player);
        PotContribution potC;
        for(int i = 0; i < potConts.size(); i++) {
            potC = potConts.get(i);
            potC.setMucked(true);
        }
        setChanged();
        notifyObservers();
    }
    
    /**return a list of contributions that aren't folded or all in, and that belong to that round (complete = false)*/
     
    /**
     * Get All the active Pot Contribution
     * @return All the active Pot Contribution
     */
    public List<PotContribution> getActiveContributions() {
        List<PotContribution> allConts = getContributions();
        List<PotContribution> activeConts = new ArrayList<PotContribution>();
        for(int i = 0; i < allConts.size(); i++) {
            PotContribution potC = allConts.get(i);
            if(!potC.getAllIn() && !potC.getMucked() && !potC.getComplete())
                activeConts.add(potC);
        }
        return activeConts;
    }
    /**
     * Get All the active Pot Contribution
     * @return All the active Pot Contribution
     */
    public List<PotContribution> getActiveContributions(PlayerHand currentPlayer) {
        List<PotContribution> allConts = getContributions();
        List<PotContribution> activeConts = new ArrayList<PotContribution>();
        for(int i = 0; i < allConts.size(); i++) {
            PotContribution potC = allConts.get(i);
            if(!potC.getAllIn() && !potC.getMucked() && !potC.getComplete()||potC.getPlayer().getId()==currentPlayer.getPlayer().getId())
                activeConts.add(potC);
        }
        return activeConts;
    }
    
    
    public boolean getClosed() {
        return closed;
    }
    
    public void setClosed(boolean closed) {
        this.closed = closed;
    }
    
    public boolean getPlayerAllIn() {
        return playerAllIn;
    }
    
    public void setPlayerAllIn(boolean allIn) {
        playerAllIn = allIn;
    }
    
    public List<PotContribution> getContributions() {
        return contributions;
    }
    

    /**
     * Dealer calls to set all PotContributions to complete to signify round ended
     */
    public void setContributionsComplete() {
        List<PotContribution> conts = getContributions();
        for(int i = 0; i < conts.size(); i++) {
            PotContribution potC = conts.get(i);
            potC.setComplete(true);
        }        
    }
    
    /**
    * Check if all the player have bet the same amout 
    * @param ActivePlayer
    * @return true if pot is complete (all active players have acted (forced == false) and have matched bets, or are all in, or are folded)
    */
    public boolean contributionsMatched(int activePlayers) {
        List<PotContribution> activeConts = getActiveContributions();
        if(activeConts.size() < activePlayers)
            return false;
        double lastBet = 0;
        for(int i = 0; i < activeConts.size(); i++) {
            PotContribution currentCont = activeConts.get(i);
            if(currentCont.getForced())
                return false;
            if(currentCont.getAmount() != lastBet && i != 0)
                return false;           
            lastBet = currentCont.getAmount();
        }
        return true;
    }
    
    public double getTotal() {
        double total = 0;
        for(int i = 0; i < contributions.size(); i++) {
            PotContribution tempCont = contributions.get(i);
            total += tempCont.getAmount();            
        }
        return total;
    }
    /**
     * Get the playerHand of all the player who have participate and hasn't mucked
     * @return
     */
    public List<PlayerHand> getPlayerHand(){
    	List<PlayerHand> listPlayerHand=new ArrayList<PlayerHand>();
    	for(int i=0;i<contributions.size();i++){
    		PlayerHand pH=contributions.get(i).getPlayer().getPlayerHand();
    		if(!contributions.get(i).getMucked()&&!listPlayerHand.contains(pH)){
    			listPlayerHand.add(contributions.get(i).getPlayer().getPlayerHand());
    		}
    	}
		return listPlayerHand;
    }

	public TablePotDAO getInfo() {
		TablePotDAO tablePotDAO=new TablePotDAO();
		tablePotDAO.setClosed(this.getClosed());
		ArrayList<PotContributionInfo> contributions=new ArrayList<PotContributionInfo>();
		for(int i=0;i<this.getContributions().size();i++){
			contributions.add(this.getContributions().get(i).getInfo());
		}
		tablePotDAO.setContributions(contributions);
		tablePotDAO.setPlayerAllIn(this.getPlayerAllIn());
		// TODO Auto-generated method stub
		return tablePotDAO;
	}
}
